home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume7 / idle.users < prev    next >
Encoding:
Internet Message Format  |  1986-12-09  |  7.6 KB

  1. Subject:  v07i089:  A simple BSD idle-users daemon
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: seismo!erix!mike (Mike Williams)
  6. Mod.sources: Volume 7, Issue 89
  7. Archive-name: idle.users
  8.  
  9. Dear Moderator,
  10.  
  11. Please find within the source code for a daemon I have been running for
  12. more than 6 months without problems on our 4.2BSD system. It simply
  13. logs off idle users afer giving them fair warning. See comments at the
  14. start of the code for more details.
  15.  
  16. I wrote this thing after I noticed the some users never logged off.  I
  17. have seen similar things on the net before, but they all seemed rather
  18. complicated, whereas this thing is very simple and easy to use and
  19. configure.  Maybe the config data should be read from a file, I thought
  20. of this but felt that the thing is so seldom reconfigured that this
  21. seemed unecessary. Have not put in any comments about this being public
  22. domain etc, but of course anyone can use this exactly as they want as
  23. far as I am concerned.
  24.  
  25. Mike Williams (mike@erix.UUCP or ...mcvax!enea!erix!mike)
  26.  
  27. #! /bin/sh
  28. # This is a shell archive.  Remove anything before this line,
  29. # then unpack it by saving it in a file and typing "sh file".
  30. # If all goes well, you will see the message "End of shell archive."
  31. # Contents:  Makefile idel.c
  32. PATH=/bin:/usr/bin:/usr/ucb; export PATH
  33. echo shar: extracting "'Makefile'" '(46 characters)'
  34. if test -f 'Makefile' ; then 
  35.   echo shar: will not over-write existing file "'Makefile'"
  36. else
  37. sed 's/^X//' >Makefile <<'@//E*O*F Makefile//'
  38. X
  39. Xidel:    idel.c
  40. X    $(CC) $(CFLAGS) -o idel idel.c
  41. @//E*O*F Makefile//
  42. if test 46 -ne "`wc -c <'Makefile'`"; then
  43.     echo shar: error transmitting "'Makefile'" '(should have been 46 characters)'
  44. fi
  45. fi # end of overwriting check
  46. echo shar: extracting "'idel.c'" '(5448 characters)'
  47. if test -f 'idel.c' ; then 
  48.   echo shar: will not over-write existing file "'idel.c'"
  49. else
  50. sed 's/^X//' >idel.c <<'@//E*O*F idel.c//'
  51. X/* idles deamon - kills off users who have not used their terminals for
  52. X * a specified time.
  53. X * Tested and run for 6 month on 4.2 BSD at site Erix.
  54. X * Change LMESSAGE, WMESSAGE, DAYOUY, NIGHTO, EVENING, MORNING and SLEEP
  55. X * to what you want locally (see comments in code) compile and run (as root).
  56. X * preferably started in /etc/rc.local by lines something like this:
  57. X *    if [ -f /usr/local/lib/id ]; then
  58. X *        /usr/local/lib/id & echo -n ' idle'    >/dev/console
  59. X *    fi
  60. X * when starting local daemons.
  61. X * The daemon wakes up every SLEEP minutes, reads UTMP and stats the terminals
  62. X * to see if when they were last used. A warning (WMESSAGE) is sent if the 
  63. X * time elapsed excedes time WARN minutes. The user is logged out and a message
  64. X * (LMESSAGE) is sent if the user has been idle for more than DAYOUT minutes
  65. X * between the hours MORNING to EVENING or else NIGHTO minutes. Error messages
  66. X * are sent to syslog LOG_CRIT. A log of users logged out is sent to syslog
  67. X * LOG_INFO. Useful for defending system managers from irate users who do 
  68. X * something stupid and log themselves out and then blame the daemon!
  69. X */
  70. X#include <utmp.h>
  71. X#include <sys/types.h>
  72. X#include <sys/time.h>
  73. X#include <sys/stat.h>
  74. X#include <sys/file.h>
  75. X#include <sgtty.h>
  76. X#include <syslog.h>
  77. X#include <setjmp.h>
  78. X#include <signal.h>
  79. X#include <strings.h>
  80. X#define UTMP "/etc/utmp"
  81. X#define LMESSAGE "\007\007\rAuto logout - too long idle time\r\n"
  82. X#define WMESSAGE "\007\007\rThe idle deamon has spotted you\r\n"
  83. X#define DAYOUT 480 /* logout after this number of idle minutes - daytime*/
  84. X#define NIGHTO 120 /* logout after this number of idle minutes - nightime */
  85. X#define MORNING 7 /* start of daytime */
  86. X#define EVENING 18 /* start of evening time */
  87. X#define WARN 90 /* start sending warnings after this time */
  88. X#define SLEEP 10 /* time (minutes) between each check */
  89. X
  90. Xjmp_buf env;
  91. Xstruct utmp ut;
  92. Xstruct stat sbuf;
  93. Xstruct timeval tv;
  94. Xstruct timezone tz;
  95. Xstruct tm *ltime;
  96. Xstruct stat sbuf;
  97. Xmain()
  98. X{
  99. X    int fd, minutes, logout;
  100. X    char fname[12];
  101. X#ifndef DEBUG
  102. X    if (fork() != 0) exit(0); /* kill off parent */
  103. X    /* close all files */
  104. X    fd = getdtablesize();
  105. X    for ( fd--; fd>=0; fd--){
  106. X        (void) close(fd);
  107. X    }
  108. X    /* create files for std{in,out,err} if they are used by syslog or some 
  109. X       such stupidity */
  110. X    if ((fd = open("/dev/null", O_RDWR)) < 0 ) exit(1);
  111. X    if ((fd = open("/dev/null", O_RDWR)) < 0 ) exit(1);
  112. X    if ((fd = open("/dev/null", O_RDWR)) < 0 ) exit(1);
  113. X    /* now remove the controling tty (if there is one) */
  114. X    if ( (fd = open("/dev/tty", O_RDWR)) >= 0 ) {
  115. X        (void) ioctl(fd, TIOCNOTTY, 0);
  116. X        (void) close(fd);
  117. X    }
  118. X#endif
  119. X    
  120. X    while (1) {
  121. X        /* open the utmp file */
  122. X        if ((fd = open(UTMP, O_RDONLY, 0)) < 0) {
  123. X            syslog(LOG_CRIT, "Idles can't open utmp");
  124. X            exit(1);
  125. X        }
  126. X        /* get the time */
  127. X        if (gettimeofday(&tv, &tz) != 0) {
  128. X            syslog(LOG_CRIT, "Idles can't get timeofday");
  129. X            exit(1);
  130. X        }
  131. X        ltime = localtime(&tv.tv_sec);
  132. X        /* work out the logout time limit */
  133. X        if ((ltime->tm_hour > MORNING) && (ltime->tm_hour < EVENING)) {
  134. X            logout = DAYOUT;
  135. X        }
  136. X        else logout = NIGHTO;
  137. X        
  138. X        /* read the utmp file, record by record until finished */
  139. X        while (read(fd, &ut, sizeof(struct utmp)) == sizeof(struct utmp)) {
  140. X            if (ut.ut_line[0] != '\0' && ut.ut_name[0] != '\0') {
  141. X                /* get the last time of use of the terminal by
  142. X                   stat-ing the terminal */
  143. X                strcpy(fname, "/dev/");
  144. X                strcat(fname, ut.ut_line);
  145. X                if (stat(fname, &sbuf) != 0) {
  146. X                    perror("idles: stat: ");
  147. X                    continue;
  148. X                }
  149. X                /* calculate the number of minutes since the terminal was last
  150. X                   acessed */
  151. X                minutes = (tv.tv_sec - sbuf.st_atime ) / 60;
  152. X                /* kill him off or warn him if he hasn't used his terminal */
  153. X                if (minutes >= logout) {
  154. X                    zap(fname, LMESSAGE, 0);
  155. X                    syslog(LOG_INFO, "Auto logout %s %s ",
  156. X                      ut.ut_name, ut.ut_line);
  157. X                }
  158. X                else if (minutes >= WARN) {
  159. X                    zap(fname, WMESSAGE, 1);
  160. X                }
  161. X            }
  162. X        }
  163. X        (void) close(fd);
  164. X        /* sleep until its time to start again */
  165. X        sleep(SLEEP * 60);
  166. X    }
  167. X}
  168. X/* kill or warn a user */
  169. Xzap(fname, message, warn)
  170. Xchar *fname, *message;
  171. X{
  172. X    int allarmed();
  173. X    struct sgttyb ttyb;
  174. X    int tfd;
  175. X    if (fork() == 0) {
  176. X        /* child kills the offender */
  177. X        /* close all files */
  178. X        tfd = getdtablesize();
  179. X        for ( tfd--; tfd>=0; tfd--){
  180. X            (void) close(tfd);
  181. X        }
  182. X        /* now remove the controling tty (if there is one) */
  183. X        if ( (tfd = open("/dev/tty", O_RDWR)) >= 0 ) {
  184. X            (void) ioctl(tfd, TIOCNOTTY, 0);
  185. X            (void) close(tfd);
  186. X        }
  187. X        /* this open will also set a new controling terminal */
  188. X        tfd = open(fname, O_RDWR, 0600) ;
  189. X        if (tfd < 0) exit(1);
  190. X        /* setup a timeout if against all odds we get hung */
  191. X        signal(SIGALRM,allarmed);
  192. X        alarm(2);
  193. X        if (setjmp(env) == 0) {
  194. X            /* do this to prevent ^S from hanging the process */
  195. X            (void) ioctl(tfd, TIOCSTART, (char *)0);
  196. X            /* toggle cbreak to disrupt any terminal paging */
  197. X            (void) ioctl(tfd, TIOCGETP, &ttyb);
  198. X            ttyb.sg_flags ^= CBREAK;
  199. X            (void) ioctl(tfd, TIOCSETP, &ttyb);
  200. X            ttyb.sg_flags ^= CBREAK;
  201. X            (void) ioctl(tfd, TIOCSETP, &ttyb);
  202. X            
  203. X            /* write out the logout message */
  204. X            write(tfd, message, strlen(message));
  205. X        
  206. X            /* flush it out for safety's sake */
  207. X            (void) ioctl(tfd, TIOCFLUSH, (char *)0);
  208. X        }
  209. X        alarm(0);
  210. X        (void) close(tfd);
  211. X        /* kill off the offender's login and exit */
  212. X        if (!warn) vhangup();
  213. X        exit(0);
  214. X    }
  215. X    /*parent: wait for the forked process*/
  216. X    while (wait(0) == 0);
  217. X}
  218. X
  219. X/* just longjmp out if timed out (SIGALRM received) */
  220. Xallarmed(sig)
  221. Xint sig;
  222. X{
  223. Xlongjmp(env,1);
  224. X}
  225. X
  226. @//E*O*F idel.c//
  227. if test 5448 -ne "`wc -c <'idel.c'`"; then
  228.     echo shar: error transmitting "'idel.c'" '(should have been 5448 characters)'
  229. fi
  230. fi # end of overwriting check
  231. echo shar: "End of shell archive."
  232. exit 0
  233.